#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Time    : 2024/3/8 17:34
# @Author  : jeff
# @FileName: thread_pool
import time
from concurrent.futures import ThreadPoolExecutor
from functools import partial
import threading

from src.utils.read_config import thread_pool_config

max_worker, wait_for_worker, time_out = thread_pool_config()


class Singleton(type):
    _instances = {}
    _lock = threading.Lock()

    def __call__(cls, *args, **kwargs):
        if cls not in cls._instances:
            with cls._lock:
                if cls not in cls._instances:
                    cls._instances[cls] = super().__call__(*args, **kwargs)
        return cls._instances[cls]


class ThreadPool(object, metaclass=Singleton):
    def __init__(self, max_workers=3, wait_for_workers=None, thread_name_prefix='ThreadPoolExecutor', timeout=None):
        self._executor = ThreadPoolExecutor(max_workers=max_workers, thread_name_prefix=thread_name_prefix)
        self._wait_for_workers = wait_for_workers
        self._timeout = timeout

    def submit(self, task, *args, **kwargs):
        task = partial(task, *args, **kwargs)
        if self._wait_for_workers is not None:
            future = self._executor.submit(task)
            if 0 < self._wait_for_workers <= self._executor._work_queue.qsize():
                self._executor._work_queue.get(timeout=self._timeout)
                return future
        else:
            return self._executor.submit(task)

    def shutdown(self, wait=True):
        self._executor.shutdown(wait=wait)

    def __del__(self):
        self._executor.shutdown(wait=False)


# Get the thread pool singleton object
thread_pool = ThreadPool(
    max_workers=int(max_worker),
    wait_for_workers=int(wait_for_worker),
    timeout=int(time_out),
    thread_name_prefix='MyThreadPool')

if __name__ == '__main__':
    # Encapsulate resource-intensive tasks into functions
    def worker(name, sleep_time):
        time.sleep(sleep_time)
        print(f'Worker {name} stopped.')
    future1 = thread_pool.submit(worker, 'Task A', 10)
    future2 = thread_pool.submit(worker, 'Task B', 5)
    future3 = thread_pool.submit(worker, 'Task C', 1)
    future4 = thread_pool.submit(worker, 'Task D', 17)
    time.sleep(20)
    thread_pool.shutdown()
